require "open-uri"
require "yaml"
require "fileutils"

require "hpricot"
require "http_helper"

include HttpHelper

class MorningStarReport
  QUERY_PAGE = "http://fund.sohu.com/r/cxo.php"
  CACHED_REPORTS = "#{RAILS_ROOT}/cached_reports"
  CACHED_REPORT_DATES = "#{CACHED_REPORTS}/report_dates.yml"
  
  attr_reader :date
  
  def self.find_all
    report_dates.map{|date| MorningStarReport.new(date)}
  end
  
  def self.find_by_date(date_string)
    report_date = report_dates.select{|date| date.to_s == date_string}.first
    return MorningStarReport.new(report_date) if report_date
  end
  
  def self.recent
    find_all.last
  end

  def self.report_dates
    if File.exist?(CACHED_REPORT_DATES) && File.ctime(CACHED_REPORT_DATES) > 1.days.ago
      return YAML.load_file(CACHED_REPORT_DATES) 
    end
  
    doc = Hpricot.parse(MorningStarReport.get(QUERY_PAGE, "gb2312"))
    date_options = (doc/"select[@id='tdate']/option").reverse
    report_dates = date_options.map{|option| Time.parse(option.inner_html).to_date }
    
    File.open(CACHED_REPORT_DATES, "w"){|out| YAML.dump report_dates, out }    
    return report_dates
  end

  def initialize(date)
    @date = date
  end
  
  def order(field, direction = :ASC)
    stock_funds.sort! do |f1, f2| 
      default_value = (direction == :DESC) ? Float::MIN : Float::MAX
      left, right = (direction == :DESC) ? [f2, f1] : [f1, f2]
      left.get_as_float(field, default_value) <=> right.get_as_float(field, default_value)
    end
  end
  
  def stock_funds
    @stock_funds ||= load_funds
  end
  
  def find_fund_by_code(code)
    stock_funds.select{|fund| fund.code == code}.first
  end
  
  private
  def report_page
    html = MorningStarReport.get(QUERY_PAGE + "?tdate=#{@date}", "gb2312")
    return html
  end
    
  def load_funds
    funds = load_funds_from_cache
    return funds if funds
  
    doc = Hpricot.parse(report_page)
    subtitles = (doc/"tr[@align='left']")
    subtable = doc.to_html.split(subtitles.first.to_html).last.split(subtitles[1].to_html).first
    subdoc = Hpricot.parse(subtable)
    funds = (subdoc/"tr").map{|tr| retrieve_fund tr }

    File.open(cached_report_path, "w"){|out| YAML.dump funds, out }
    return funds
  end
  
  def load_funds_from_cache
    return nil unless File.exist? cached_report_path
    Fund::FIELDS
    YAML.load_file cached_report_path
  end
  
  def retrieve_fund(tr)
    fund = Fund.new
    texts = (tr/"td").map{|td| td.inner_text}
    Fund.fields.each_index do |i|
      fund.send(:"#{Fund.fields[i]}=", texts[i])
    end
    return fund
  end
  
  def cached_report_path
    "#{CACHED_REPORTS}/#{@date}.yml"
  end
  
end